package com.dd.cloud.user.service.mechan.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.MechanConstants;
import com.dd.cloud.user.entity.mechan.MechanRank;
import com.dd.cloud.user.entity.mechan.MechanUser;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.user.mapper.mechan.MechanUserMapper;
import com.dd.cloud.user.req.mechan.MechanUserAddReq;
import com.dd.cloud.user.req.mechan.MechanUserPageReq;
import com.dd.cloud.user.req.mechan.MechanUserUpdateReq;
import com.dd.cloud.user.res.mechan.MechanUserLoginRes;
import com.dd.cloud.user.res.mechan.MechanUserPage;
import com.dd.cloud.user.service.mechan.IMechanRankService;
import com.dd.cloud.user.service.mechan.IMechanUserService;
import com.dd.cloud.common.config.servlet.JwtUtils;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.common.config.sms.SmsComponent;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.CodecUtils;
import com.dd.cloud.common.utils.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * <p>
 * 机构账号表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-04-27
 */
@Service
public class MechanUserServiceImpl extends ServiceImpl<MechanUserMapper, MechanUser> implements IMechanUserService {
    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private IMechanRankService mechanRankService;
    @Autowired
    private SmsComponent smsComponent;


    /**
     * 机构管理员用户登录 验证码
     *
     * @param request
     * @param response
     * @param phone
     * @param code
     * @return
     */
    @Override
    public MechanUserLoginRes merchantUserLoginCode(HttpServletRequest request, HttpServletResponse response, String phone, String code) {
        if (StringUtils.isBlank(code)) {
            throw new ZekeException(ZkExceptionEnum.INVALID_VERIFY_CODE);
        }
        //查询账号
        QueryWrapper<MechanUser> q = new QueryWrapper<>();
        q.lambda().eq(MechanUser::getAccount, phone);
        q.lambda().ne(MechanUser::getStatus, MechanConstants.MechanUserStatus.DEL);
        MechanUser user = getOne(q);
        MechanRank mr = new MechanRank();
        if (user == null) {
            throw new ZekeException(ZkExceptionEnum.ACCOUNT_NOT_FOUND);
        } else {
            smsComponent.verifyPhoneCode(phone, code);
            //校验账号状态
            switch (user.getStatus()) {
                case MechanConstants.MechanUserStatus.DEL:
                    throw new ZekeException(ZkExceptionEnum.ACCOUNT_IS_DELETED);
                case MechanConstants.MechanUserStatus.DISABLEMECHAN:
                case MechanConstants.MechanUserStatus.DISABLEADMIN:
                    throw new ZekeException(ZkExceptionEnum.ACCOUNT_IS_FORBIDDEN);
                default:
            }
            QueryWrapper<MechanRank> qw = new QueryWrapper<>();
            qw.lambda().eq(MechanRank::getId, user.getMechanId());
            mr = mechanRankService.getOne(qw);
            switch (mr.getStatus()) {
                case MechanConstants.MechanStatus.DEL:
                    throw new ZekeException(400, "租户已被删除");
                case MechanConstants.MechanStatus.DISABLEADMIN:
                    throw new ZekeException(400, "租户已被禁用");
                case MechanConstants.MechanStatus.UN_REVIEW:
                case MechanConstants.MechanStatus.REVIEW_REJECT:
                    throw new ZekeException(400, "租户审核中或未审核通过");
                default:
            }
            jwtUtils.createToken(new LoginInfo(user.getId(), user.getMechanId(), LoginInfo.UserType.MECHAN, user.getName(), jwtUtils.getUserAgent(request)), request, response);
        }
        MechanUserLoginRes res = new MechanUserLoginRes();
        BeanUtils.copyProperties(user, res);
        res.setMechanName(mr.getName());
        return res;
    }

    /**
     * 机构管理员用户登录 密码
     *
     * @param account
     * @param password
     * @return
     */
    @Override
    public MechanUserLoginRes merchantUserLoginPwd(HttpServletRequest request, HttpServletResponse response, String account, String password) {
        //查询账号
        QueryWrapper<MechanUser> q = new QueryWrapper<>();
        q.lambda().eq(MechanUser::getAccount, account);
        q.lambda().ne(MechanUser::getStatus, MechanConstants.MechanUserStatus.DEL);
        MechanUser user = getOne(q);
        if (user == null) {
            throw new ZekeException(ZkExceptionEnum.ACCOUNT_NOT_FOUND);
        }
        //校验账号状态
        switch (user.getStatus()) {
            case MechanConstants.MechanUserStatus.DEL:
                throw new ZekeException(ZkExceptionEnum.ACCOUNT_IS_DELETED);
            case MechanConstants.MechanUserStatus.DISABLEMECHAN:
            case MechanConstants.MechanUserStatus.DISABLEADMIN:
                throw new ZekeException(ZkExceptionEnum.ACCOUNT_IS_FORBIDDEN);
            default:
        }
        QueryWrapper<MechanRank> qw = new QueryWrapper<>();
        qw.lambda().eq(MechanRank::getId, user.getMechanId());
        MechanRank mr = mechanRankService.getOne(qw);
        switch (mr.getStatus()) {
            case MechanConstants.MechanStatus.DEL:
                throw new ZekeException(400, "租户已被删除");
            case MechanConstants.MechanStatus.DISABLEADMIN:
                throw new ZekeException(400, "租户已被禁用");
            default:
        }
        //校验密码
        q.lambda().eq(MechanUser::getPassword, CodecUtils.md5Hex(password, user.getSalt()));
        user = getOne(q);
        if (user == null) {
            throw new ZekeException(ZkExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //生成token并写入cookie
        jwtUtils.createToken(new LoginInfo(user.getId(), user.getMechanId(), LoginInfo.UserType.MECHAN, user.getName(), jwtUtils.getUserAgent(request)), request, response);
        MechanUserLoginRes res = new MechanUserLoginRes();
        BeanUtils.copyProperties(user, res);
        res.setMechanName(mr.getName());
        return res;
    }

    /**
     * 机构管理员用户找回密码
     *
     * @param phone
     * @param code
     * @param pwd1
     * @param pwd2
     */
    @Override
    public void findMerchantUserPwd(String phone, String code, String pwd1, String pwd2) {
        if (StringUtils.isBlank(code)) {
            throw new ZekeException(ZkExceptionEnum.INVALID_VERIFY_CODE);
        }
        if (!Objects.equals(pwd1, pwd2)) {
            throw new ZekeException(400, "两次密码不一致");
        }
        smsComponent.verifyPhoneCode(phone, code);
        String salt = CodecUtils.generateSalt();
        pwd2 = CodecUtils.md5Hex(pwd2, salt);
        UpdateWrapper<MechanUser> uw = new UpdateWrapper<>();
        uw.lambda().eq(MechanUser::getAccount, phone);
        uw.lambda().set(MechanUser::getSalt, salt);
        uw.lambda().set(MechanUser::getPassword, pwd2);
        boolean flag = update(uw);
        if (!flag) {
            throw new ZekeException(ZkExceptionEnum.ACCOUNT_NOT_FOUND);
        }
    }

    /**
     * 机构管理员用户修改密码
     *
     * @param oldPwd
     * @param newPwd1
     * @param newPwd2
     */
    @Override
    public void updateMerchantUserPwd(String oldPwd, String newPwd1, String newPwd2) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.MECHAN).get();
        MechanUser mu = getById(loginInfo.getId());
        oldPwd = CodecUtils.md5Hex(oldPwd, mu.getSalt());
        if (!Objects.equals(oldPwd, mu.getPassword())) {
            throw new ZekeException(400, "原密码错误");
        }
        mu.setSalt(CodecUtils.generateSalt());
        mu.setPassword(CodecUtils.md5Hex(newPwd2, mu.getSalt()));
        updateById(mu);
    }

    /**
     * 分页查询机构管理员
     *
     * @param req
     * @return
     */
    @Override
    public Page<MechanUserPage> getMechanUserPage(MechanUserPageReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.MECHAN).get();
        Page<MechanUserPage> page = req.pagePojo();
        req.setMechanId(loginInfo.getMechanId());
        page = getBaseMapper().getMechanUserPage(page, req);
        return page;
    }

    /**
     * 添加管理员
     *
     * @param req
     */
    @Override
    public void addMechanUser(MechanUserAddReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.MECHAN).get();
        MechanRank mechanRank = mechanRankService.getById(loginInfo.getMechanId());
        if (mechanRank == null || mechanRank.getStatus() == MechanConstants.MechanStatus.DEL) {
            throw new ZekeException(ZkExceptionEnum.MECHAN_NOT_FOUND);
        }
        if (mechanRank.getStatus() == MechanConstants.MechanStatus.DISABLEADMIN) {
            throw new ZekeException(400, "机构已禁用");
        }
        QueryWrapper<MechanUser> qw = new QueryWrapper<>();
        qw.lambda().ne(MechanUser::getStatus, MechanConstants.MechanUserStatus.DEL)
                .and(w ->
                        w.eq(MechanUser::getAccount, req.getAccount())
                                .or()
                                .eq(MechanUser::getPhone, req.getPhone()));
        int count = count(qw);
        if (count > 0) {
            throw new ZekeException(ZkExceptionEnum.PHONE_IS_EXISTS);
        }
        if(!req.getPassword().equals(req.getResPwd())){
            throw new ZekeException(400, "密码不一致");
        }
        MechanUser mechanUser = new MechanUser();
        BeanUtils.copyProperties(req, mechanUser);
        mechanUser.setStatus(MechanConstants.MechanUserStatus.NORMAL);
        mechanUser.setCreateDate(LocalDateTime.now());
        mechanUser.setCreateId(loginInfo.getId());
        mechanUser.setCreateName(loginInfo.getName());
        mechanUser.setMechanId(loginInfo.getMechanId());
        mechanUser.setType(MechanConstants.MechanUserType.PLAIN);
        // 对密码进行加密
        String salt = CodecUtils.generateSalt();
        mechanUser.setSalt(salt);
        String password = req.getPassword();
        if (StringUtils.isBlank(password)){
            password = mechanUser.getPhone().substring(mechanUser.getPhone().length() - 6);
        }
        mechanUser.setPassword(CodecUtils.md5Hex(password, mechanUser.getSalt()));
        boolean i = save(mechanUser);
        if (!i) {
            throw new ZekeException(ZkExceptionEnum.ADD_ERROR);
        }
    }

    /**
     * 修改单位管理员信息
     *
     * @param req
     */
    @Override
    public void updateMechanUser(MechanUserUpdateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.MECHAN).get();
        MechanUser mechanUser = getById(req.getId());
        if (mechanUser == null) {
            throw new ZekeException(ZkExceptionEnum.ACCOUNT_NOT_FOUND);
        }
        if (mechanUser.getType() == MechanConstants.MechanUserType.ADMIN){
            throw new ZekeException(400, "不能编辑超级管理员");
        }
        QueryWrapper<MechanUser> qw = new QueryWrapper<>();
        qw.lambda().ne(MechanUser::getStatus, MechanConstants.MechanUserStatus.DEL)
                .ne(MechanUser::getPhone, mechanUser.getPhone())
                .and(w ->
                        w.eq(MechanUser::getAccount, req.getAccount())
                                .or()
                                .eq(MechanUser::getPhone, req.getPhone()));
        int count = count(qw);
        if (count > 0) {
            throw new ZekeException(ZkExceptionEnum.PHONE_IS_EXISTS);
        }
        if (!StringUtils.isBlank(req.getPassword())) {
            mechanUser.setPassword(CodecUtils.md5Hex(req.getPassword(), mechanUser.getSalt()));
        }
        if (!StringUtils.isBlank(req.getName())) {
            mechanUser.setName(req.getName());
        }
        if (!StringUtils.isBlank(req.getPhone())) {
            mechanUser.setPhone(req.getPhone());
        }
        if (!StringUtils.isBlank(req.getAccount())) {
            mechanUser.setAccount(req.getAccount());
        }
        updateById(mechanUser);
    }

    /**
     * 修改单位管理员状态
     *
     * @param id
     * @param status
     */
    @Override
    public void updateMechanUserStatus(Integer id, Integer status) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.MECHAN).get();

        MechanUser mechanUser = getById(id);
        if (mechanUser == null) {
            throw new ZekeException(ZkExceptionEnum.ACCOUNT_NOT_FOUND);
        }
        if (mechanUser.getType() == MechanConstants.MechanUserType.ADMIN){
            throw new ZekeException(400, "不能编辑超级管理员");
        }
        if (loginInfo.getId().equals(id)){
            throw new ZekeException(400, "不能操作自己的账号");
        }
        if (mechanUser.getStatus().equals(status)) {
            return;
        }
        if (!ObjectUtils.refrect(MechanConstants.MechanUserStatus.class, status)){
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        mechanUser.setStatus(status);
        boolean i = updateById(mechanUser);
        if (!i) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }

    /**
     * 确认手机号是否使用
     * @param phone 手机号
     * @return
     */
    @Override
    public boolean checkPhoneUsed(String phone) {
        QueryWrapper<MechanUser> qs = new QueryWrapper<>();
        qs.lambda().ne(MechanUser::getStatus, MechanConstants.MechanUserStatus.DEL);
        qs.lambda().and(wrapper -> wrapper.eq(MechanUser::getAccount, phone)
                .or().eq(MechanUser::getPhone, phone)
        );
        MechanUser mechanUser = getOne(qs);
        if (mechanUser != null){
            return true;
        }
        return false;
    }

    /**
     * 重置超管密码
     * @param mechanId
     */
    @Override
    public void resetAdminUserPwd(Integer mechanId) {
        MechanRank mechanRank = mechanRankService.getById(mechanId);
        if (mechanRank == null){
            throw new ZekeException(400,"机构不存在");
        }
        QueryWrapper<MechanUser> qw = new QueryWrapper<>();
        qw.lambda().eq(MechanUser::getMechanId, mechanId)
                .eq(MechanUser::getType, MechanConstants.MechanUserType.ADMIN)
                .ne(MechanUser::getStatus,MechanConstants.MechanUserStatus.DEL);
        MechanUser mechanUser = getOne(qw);
        if (mechanUser == null){
            throw new ZekeException(400,"机构超管不存在");
        }
        String password = mechanUser.getPhone().substring(mechanUser.getPhone().length() - 6);
        mechanUser.setPassword(CodecUtils.md5Hex(password, mechanUser.getSalt()));
        boolean i = updateById(mechanUser);
        if (!i){
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }
}
